package eHealth.android.client;

import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.InputFilter;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import eHealth.android.Helpers.InputFilterMinMax;
import eHealth.android.Helpers.InputFilterMinMaxDecimal;
import eHealth.android.REST.RESTMethods;

/**
 * 
 * @author Thomas Rouvinez
 * Date 08.03.2012
 *
 * Goal : create a form to get daily information and 
 * create a record which will be sent to the server
 *
 */
public class AddRecord extends Activity implements OnClickListener{

	// ----------------------------------------------------------------------------------------------
	// Variables.
	// ----------------------------------------------------------------------------------------------
	
	/**
	 * Buttons for user interactions.
	 */
	private Button saveRecord, datePicker;

	/**
	 * TextView to display the user selected date.
	 */
	private TextView currentDate;

	/**
	 * Integer vector for types of medical data.
	 */
	private int types[] = new int[5];
	
	/**
	 * Storage of editTexts for easier processing using for loops.
	 */
	private EditText editText[] = new EditText[6];

	/**
	 * EditTexts for all the types of medical data.
	 */
	private EditText bloodSugar, bloodPressureSystolic, bloodPressureDiastolic, 
	bpm, weight,insulinQuantityTaken;

	/**
	 * Spinners for user input of category and insulin type.
	 */
	private Spinner category, insulinType;

	/**
	 * Aquire current date.
	 */
	private Date date = new Date();
	
	/**
	 * Calendar object for operations on dates.
	 */
	private Calendar calendar = Calendar.getInstance();
	
	/**
	 * Integer for hour value initialization.
	 */
	private int mHour = date.getHours();
	
	/**
	 * Integer for minutes value initialization.
	 */
	private int mMinute = date.getMinutes();
	
	/**
	 * Integer for day of month value initialization.
	 */
	private int mDay = calendar.get(Calendar.DAY_OF_MONTH);
	
	/**
	 * Integer for month value initialization.
	 */
	private int mMonth = date.getMonth() + 1;
	
	/**
	 * Integer for year value initialization.
	 */
	private int mYear = date.getYear() + 1900;

	// ----------------------------------------------------------------------------------------------
	// Android methods.
	// ----------------------------------------------------------------------------------------------

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Set full screen application.
		requestWindowFeature(Window.FEATURE_NO_TITLE);   
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,    
				WindowManager.LayoutParams.FLAG_FULLSCREEN);

		// Set content view.
		setContentView(R.layout.addrecord);

		// Assign the buttons.
		assignGUI();
	}

	/** Called when the activity starts once it is created.<br>
	 * In addition we create here the listeners and set for the first time the dates. */
	@Override
	protected void onStart(){
		super.onStart();

		// Add listeners to the buttons.
		setListeners();

		// Set important values.
		updateDate();
	}

	// ----------------------------------------------------------------------------------------------
	// Option menu.
	// ---------------------------------------------------------------------------------------------- 

	/**
	 * Create option menu entries.
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, 1000, 1, "Help").setIcon(android.R.drawable.ic_menu_help);

		return super.onCreateOptionsMenu(menu);
	}

	/**
	 * Set listeners and actions to take for menu entries buttons.
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item){
		switch (item.getItemId()) {

		case 1000:
			// Help button.
			final AlertDialog alertDialog = new AlertDialog.Builder(AddRecord.this).create();
			alertDialog.setTitle(getString(R.string.MenuEntryHelpLabel));
			alertDialog.setMessage(getString(R.string.MenuEntryHelpTextAddRecord));

			// OK button of the help dialog.
			alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					// Do nothing.
				}
			});
			alertDialog.setIcon(R.drawable.ic_launcher);
			alertDialog.show();
			break;

			// Default action.
		default:
			break;
		}

		return super.onOptionsItemSelected(item);
	}

	// ----------------------------------------------------------------------------------------------
	// Methods.
	// ---------------------------------------------------------------------------------------------- 

	/**
	 * Link local graphical objects to GUI objects.
	 */
	private void assignGUI(){
		saveRecord = (Button)findViewById(R.id.button_SaveRecord);
		datePicker = (Button)findViewById(R.id.button_DatePicker);

		currentDate = (TextView)findViewById(R.id.textView_CurrentDate);
		currentDate.setText(date.toGMTString());

		// Define fields with their respective validations.
		bloodSugar = (EditText)findViewById(R.id.editText_BloodSugar);
		bloodSugar.setFilters(new InputFilter[]{ new InputFilterMinMaxDecimal(0.0, 200.0)});

		bloodPressureSystolic = (EditText)findViewById(R.id.EditText_BloodPressureSy);
		bloodPressureSystolic.setFilters(new InputFilter[]{ new InputFilterMinMaxDecimal(0.0, 300.0)});

		bloodPressureDiastolic = (EditText)findViewById(R.id.EditText_BloodPressureDi);
		bloodPressureDiastolic.setFilters(new InputFilter[]{ new InputFilterMinMaxDecimal(0.0, 300.0)});

		bpm = (EditText)findViewById(R.id.EditText_BPM);
		bpm.setFilters(new InputFilter[]{ new InputFilterMinMax(1, 300)});

		weight = (EditText)findViewById(R.id.EditText_Weight);
		weight.setFilters(new InputFilter[]{ new InputFilterMinMaxDecimal(0.0, 400.0)});

		insulinQuantityTaken = (EditText)findViewById(R.id.EditText_InsulinQuantityTaken);
		insulinQuantityTaken.setFilters(new InputFilter[]{ new InputFilterMinMax("0", "100")});

		category = (Spinner)findViewById(R.id.spinner_Category);
		insulinType = (Spinner)findViewById(R.id.Spinner_InsulinType);

		// Insert all the editTexts in a table for further automatic processing.
		editText[0] = bloodSugar;
		editText[1] = bloodPressureSystolic;
		editText[2] = bloodPressureDiastolic;
		editText[3] = bpm;
		editText[4] = weight;
		editText[5] = insulinQuantityTaken;

		// Define the types of each fields according to the editText[].
		types[0] =  0;
		types[1] =  4;
		types[2] =  3;
		types[3] =  5;
		types[4] =  2;
	}

	/**
	 * Set local listener for buttons.
	 */
	private void setListeners(){
		saveRecord.setOnClickListener(this);
		datePicker.setOnClickListener(this);
	}

	/**
	 * Buttons' listeners implementation.
	 */
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button_SaveRecord:
			// Save record button action.
			// Check if there is a value in at least one EditText.
			int charsCount = 0;					// Number of total characters typed by the user in the GUI.

			for(int i = 0 ; i < editText.length; i++){
				charsCount = charsCount + editText[i].getText().length();
			}

			if(charsCount > 0){
				// Sending the information.
				try {
					// Create list of objects for the medical data to send to the server.
					JSONArray medicalData = CreateMedicalArray(editText);

					// Send the record to the server.
					RESTMethods.sendRecord(medicalData);

					// Close current instance of the 'AddRecord' screen.
					eHealth.android.client.Menu.statisticsAlreadyProcessed = false;
					this.finish();

				} catch (Exception e) {
					Toast.makeText(eHealth.android.client.Menu.context, e.toString(), 1000).show();
				}
			}
			else{
				// Inform the user that he must enter a value.
				Toast.makeText(this, R.string.ErrorNoValueEntered, 1000).show();
			}
			break;

		case R.id.button_DatePicker:
			// Show pop-up for date values.
			showDialog(0);
			break;

		default:
			break;
		}	
	}

	// ----------------------------------------------------------------------------------------------------
	// Date and time pickers methods.
	// ----------------------------------------------------------------------------------------------------

	/**
	 * The call back received when the user "sets" the date in the dialog.
	 */
	private DatePickerDialog.OnDateSetListener mDateSetListener =
			new DatePickerDialog.OnDateSetListener() {
		public void onDateSet(DatePicker view, int year, 
				int monthOfYear, int dayOfMonth) {
			mYear = year;
			mMonth = monthOfYear + 1;
			mDay = dayOfMonth;
			updateDate();
		}
	};

	/**
	 * Create dialog screens for time and date pickers.
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		if(id == 0)
			return new DatePickerDialog(this,
					mDateSetListener,
					mYear, mMonth -1, mDay);

		return null;
	}

	/**
	 * Rebuild a date from values.
	 * @param year
	 * @param month
	 * @param day
	 * @param hour
	 * @param minute
	 * @return newly build date.
	 */
	private Date buildDateObject(int year, int month, int day, int hour, int minute){

		Date dateBuilder = new Date();
		String date = year + "/" + month + "/" + day;

		// Parsing the string to set year, month and day values.
		try {
			SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
			dateBuilder = formatter.parse(date);
		} catch (java.text.ParseException e) {
			e.printStackTrace();
		}

		return dateBuilder;
	}

	/**
	 * Update display of dates.
	 */
	private void updateDate(){
		// Prepare string of the date for user feedback.
		String dateCustom = "" + mDay + " of " + new DateFormatSymbols().getMonths()[mMonth-1] + " / " + mYear
				+ "  " + mHour + ":" + mMinute + " GMT";

		currentDate.setText(dateCustom);
	}

	// ----------------------------------------------------------------------------------------------------
	// REST + JSON processing.
	// ----------------------------------------------------------------------------------------------------

	/**
	 * Create an array of JSON objects with the medical data of the current record.
	 * @param edittexts
	 * @return A JSONArray ready to be shipped to the medical service.
	 * @throws JSONException
	 */
	private JSONArray CreateMedicalArray(EditText[] edittexts) throws JSONException{

		// Variables.
		JSONArray medicalDataArray = new JSONArray();
		JSONObject medicalData;		

		// Update date object with current values.
		this.date = buildDateObject(mYear, mMonth, mDay, mHour, mMinute);

		String newDate = "";

		if(mDay < 10){
			newDate += "0" + mDay + ".";
		}
		else{
			newDate += mDay + ".";
		}
		if(mMonth < 10){
			newDate += "0" + mMonth + ".";
		}
		else{
			newDate += mMonth + ".";
		}

		newDate += mYear + ".";

		// Create an array of medicalData with the user input in the fields.
		for(int i = 0 ; i < 5 ; i++){
			// Check if value from field is different from default value (test all but insuline quantity).
			if(edittexts[i].getText().length() != 0){
				// Create new JSON Object medical data.
				medicalData = new JSONObject();
				medicalData.put("value", Double.parseDouble(edittexts[i].getText().toString()));
				medicalData.put("date", newDate);
				medicalData.put("category", category.getSelectedItemId());
				medicalData.put("type", types[i]);

				// Add new medicalData to list.
				medicalDataArray.put(medicalData);
			}	
		}

		// Special case : insuline (edittexts[5]).
		if(edittexts[5].getText().length() != 0){
			// Create new JSON Object medical data
			medicalData = new JSONObject();

			medicalData.put("value", Double.parseDouble(edittexts[5].getText().toString()));
			medicalData.put("date", newDate);
			medicalData.put("category", category.getSelectedItemId());

			if(insulinType.getSelectedItemPosition() == 0){
				medicalData.put("type", insulinType.getSelectedItemId() + 11); // view technical documentation on insulin types
			}
			else{
				medicalData.put("type", insulinType.getSelectedItemId() + 12); // view technical documentation on insulin types
			}

			// Add new medicalData to list.
			medicalDataArray.put(medicalData);
		}

		return medicalDataArray;
	}
}